/*
 *
 *  * Copyright (C) 2016 CS ROMANIA
 *  *
 *  * This program is free software; you can redistribute it and/or modify it
 *  * under the terms of the GNU General Public License as published by the Free
 *  * Software Foundation; either version 3 of the License, or (at your option)
 *  * any later version.
 *  * This program is distributed in the hope that it will be useful, but WITHOUT
 *  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 *  * more details.
 *  *
 *  * You should have received a copy of the GNU General Public License along
 *  *  with this program; if not, see http://www.gnu.org/licenses/
 *
 */

package org.esa.snap.ui.tooladapter.dialogs.components;

import java.util.function.Function;
import java.util.function.Predicate;

/**
 * Models a relation between two entity fields such that, if one field changes, the other may change based on the new
 * value of the first field.
 *
 * @param <S>   The source field type
 * @param <T>   The target field type
 *
 * @author Cosmin Cara
 */
public class FieldChangeTrigger<S, T> implements Function<S, T> {
    private String targetFieldName;
    private Predicate<S> condition;
    private Function<S, T> action;

    /**
     * Creates a field change trigger with just an action.
     *
     * @param fieldName   The target field name
     * @param action            The action that will set the target
     * @param <K>               The source field type
     * @param <V>               The target field type
     */
    public static <K,V> FieldChangeTrigger<K, V> create(String fieldName, Function<K, V> action) {
        return create(fieldName, action, null);
    }
    /**
     * Creates a field change trigger with an action that will execute based on a condition.
     *
     * @param fieldName   The target field name
     * @param action            The action that may set the target
     * @param condition         The condition to check before performing the action
     * @param <K>               The source field type
     * @param <V>               The target field type
     */
    public static <K,V> FieldChangeTrigger<K, V> create(String fieldName, Function<K, V> action, Predicate<K> condition) {
        return new FieldChangeTrigger<K, V>(fieldName, action, condition);
    }

    private FieldChangeTrigger(String fieldName, Function<S, T> action, Predicate<S> condition) {
        this.targetFieldName = fieldName;
        this.action = action;
        this.condition = condition;
    }

    /**
     * Returns the target field name
     */
    public String getTargetFieldName() {
        return targetFieldName;
    }

    public boolean canApply(S input) {
        return condition == null || condition.test(input);
    }

    public T apply(S input) {
        return canApply(input) ?
            action != null ? action.apply(input) : null : null;
    }
}
